package serv;

import java.net.Socket;
import javax.xml.parsers.*;
import org.w3c.dom.*;

import java.text.DateFormat;
import java.io.*;

import org.xml.sax.InputSource;
import org.xmldb.api.*;
import org.xmldb.api.base.*;
import org.xmldb.api.base.Collection;
import org.exist.xmldb.*;

public class ServerSocketThread extends Thread{
	private Socket socket;
	private final double LIM_NIVEL = 0.35;
	private final String URI = "xmldb:exist://localhost:8080/db/programa_fidelidade/";
	private final String USR = "admin";
	private final String PSW = "admin";
	
	public ServerSocketThread(Socket socket) {
		super();
		this.socket = socket;
	}
	
	public void run() {
		XQueryService xqSrvc;
		
		try {		
			DocumentBuilder xmlBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			Document xmlDoc = xmlBuilder.parse(socket.getInputStream());
			
			Collection xmlCartoes = DatabaseManager.getCollection(URI + "cartoes", USR, PSW);
			xqSrvc = (XQueryService)xmlCartoes.getService("XQueryService", "1.0");
			xqSrvc.setProperty("indent", "yes");
			ResourceSet xmlMaxCartao = xqSrvc.query("return max(//numero)");			
			
			if (xmlDoc.getDocumentElement().getNodeName().equals("cliente")) {
				Collection colClientes = DatabaseManager.getCollection(URI + "clientes", USR, PSW);
				
				
				xqSrvc = (XQueryService)colClientes.getService("XQueryService", "1.0");
				xqSrvc.setProperty("indent", "yes");
				
				//Verifica se o cpf do cliente já existe no BD e caso positivo
				//recupera o cliente e envia seu número de cartão.
				//Caso negativo cria um novo cliente.
				ResourceSet resClientes = xqSrvc.query("//cliente[cpf/text() = " +
													  xmlDoc.getElementsByTagName("cpf").item(0).getNodeValue() +
													  "]");
				if (resClientes.getSize() == 0) {
					Resource xmlRes = colClientes.createResource(null, "XMLResource");
					
					Element tagCartao = xmlDoc.createElement("cartao");
					tagCartao.setNodeValue(xmlMaxCartao.getResource(0).getContent().toString());
					xmlDoc.getDocumentElement().appendChild(tagCartao);
					
					xmlRes.setContent(xmlDoc.getTextContent());
					colClientes.storeResource(xmlRes);
					
					Collection colContas = DatabaseManager.getCollection(URI + "contas", USR, PSW);
					ContaFidelidade novaConta = new ContaFidelidade();
					
					Document xmlNovaConta = xmlBuilder.newDocument();
					Element raizConta = xmlNovaConta.createElement("conta");
					Element pontosConta = xmlNovaConta.createElement("pontos");
					pontosConta.setNodeValue(String.valueOf(novaConta.getPontos()));
					Element nivelConta = xmlNovaConta.createElement("nivel");
					nivelConta.setNodeValue(String.valueOf(novaConta.getNivel()));
					Element cartaoConta = xmlNovaConta.createElement("cartao");
					cartaoConta.setNodeValue(tagCartao.getNodeValue());
					raizConta.appendChild(pontosConta);
					raizConta.appendChild(nivelConta);
					raizConta.appendChild(cartaoConta);
					xmlNovaConta.appendChild(raizConta);
					
					xmlRes = colContas.createResource(null, "XMLResource");
					xmlRes.setContent(xmlNovaConta.getTextContent());
					colContas.storeResource(xmlRes);
					
					Collection colCartoes = DatabaseManager.getCollection(URI + "cartoes", USR, PSW);
					Cartao novoCartao = new Cartao();
					
					Document xmlNovoCartao = xmlBuilder.newDocument();
					Element raizCartao = xmlNovoCartao.createElement("cartao");
					Element numCartao = xmlNovoCartao.createElement("numero");
					numCartao.setNodeValue(tagCartao.getNodeValue());
					Element dataEmisCartao = xmlNovoCartao.createElement("data-emissao");
					dataEmisCartao.setNodeValue(DateFormat.getDateInstance().format(novoCartao.getDataEmissao()));
					Element cpfCartao = xmlNovoCartao.createElement("cpf");
					cpfCartao.setNodeValue(xmlDoc.getElementsByTagName("cpf").item(0).getNodeValue());
					raizCartao.appendChild(numCartao);
					raizCartao.appendChild(dataEmisCartao);
					raizCartao.appendChild(cpfCartao);
					xmlNovoCartao.appendChild(raizCartao);
					
					xmlRes = colCartoes.createResource(null, "XMLResource");
					xmlRes.setContent(xmlNovoCartao.getTextContent());
					colCartoes.storeResource(xmlRes);
					
					new DataOutputStream(socket.getOutputStream()).writeUTF(xmlMaxCartao.getResource(0).getContent().toString());
				}
				else {
					Document xmlCliente = xmlBuilder.parse(new InputSource(new StringReader(resClientes.getResource(0).getContent().toString())));
					
					new DataOutputStream(socket.getOutputStream()).writeUTF(xmlCliente.getElementsByTagName("cartao").item(0).getNodeValue());
				}
			}
			else if (xmlDoc.getDocumentElement().getNodeName().equals("transacoes")) {
				int i;
				NodeList nlTransacoes = xmlDoc.getElementsByTagName("transacao");
				
				Collection colContas = DatabaseManager.getCollection(URI + "contas", USR, PSW);
				for (i=0;i < nlTransacoes.getLength();i++) {
					Document xmlTrans = xmlBuilder.parse(new InputSource(new StringReader(nlTransacoes.item(i).getTextContent())));
					xqSrvc = (XQueryService)colContas.getService("XQueryService", "1.0");
					xqSrvc.setProperty("indent", "yes");
				
					ResourceSet resContas = xqSrvc.query("//conta[cartao = " + xmlDoc.getElementsByTagName("cartao").item(0).getNodeValue() + "]");
					
					Document xmlConta = xmlBuilder.parse(new InputSource(new StringReader(resContas.getResource(0).getContent().toString())));
					ContaFidelidade conta = new ContaFidelidade();
					conta.setPontos(Integer.parseInt(xmlConta.getElementsByTagName("pontos").item(0).getNodeValue()));
					
					if (xmlTrans.getDocumentElement().getAttribute("debito").equals("false")) {
						conta.ganhar((int)Math.ceil(Double.parseDouble(xmlConta.getElementsByTagName("nivel").item(0).getNodeValue() +
								     Double.parseDouble(xmlTrans.getElementsByTagName("valor_unit").item(0).getNodeValue()) +
								     Integer.parseInt(xmlTrans.getElementsByTagName("quant").item(0).getNodeValue()))));
						
						if (conta.getNivel() <= LIM_NIVEL)
							conta.setNivel(0.1 + conta.getPontos() / 10000);
					}
					else {
						conta.gastar(Double.parseDouble(xmlTrans.getElementsByTagName("valor_unit").item(0).getNodeValue()) +
							     Integer.parseInt(xmlTrans.getElementsByTagName("quant").item(0).getNodeValue()));
					}
					
					xmlConta.getElementsByTagName("pontos").item(0).setNodeValue(String.valueOf(conta.getPontos()));
					xmlConta.getElementsByTagName("nivel").item(0).setNodeValue(String.valueOf(conta.getNivel()));
					
					colContas.removeResource(resContas.getResource(0));
					Resource xmlRes = colContas.createResource(null, "XMLResource");
					xmlRes.setContent(xmlConta.getTextContent());
					colContas.storeResource(xmlRes);
					
					Collection colTransacoes = DatabaseManager.getCollection(URI + "transacoes", USR, PSW);
					xmlRes = colTransacoes.createResource(null, "XMLResource");
					xmlRes.setContent(xmlDoc.getTextContent());
					colTransacoes.storeResource(xmlRes);
					
					new DataOutputStream(socket.getOutputStream()).writeUTF("OK!");
				}
			}
			else if (xmlDoc.getDocumentElement().getNodeName().equals("empresa")) {
				Collection colEmpresas = DatabaseManager.getCollection(URI + "empresas", USR, PSW);
				Resource xmlRes = colEmpresas.createResource(null, "XMLResource");
				xmlRes.setContent(xmlDoc.getTextContent());
				colEmpresas.storeResource(xmlRes);
				
				new DataOutputStream(socket.getOutputStream()).writeUTF("OK!");
			}
			else {
				new DataOutputStream(socket.getOutputStream()).writeUTF("XML Desconhecido");
			}
			
		}
		catch (Exception e) {
			try {
				new DataOutputStream(socket.getOutputStream()).writeUTF(e.getMessage());
			}
			catch (Exception e1) {
				e1.printStackTrace();
			}
			
		}
	}

}
